{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Pa8905-YsHAn"
      },
      "source": [
        "# Fine-tune a Mistral-7b model with DPO (Direct Preference Optimization)\n",
        "\n",
        "### Checkout my [Twitter(@rohanpaul_ai)](https://twitter.com/rohanpaul_ai) for daily LLM bits"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_zIBL8IssExG"
      },
      "outputs": [],
      "source": [
        "!pip install --upgrade trl peft accelerate bitsandbytes datasets auto-gptq optimum huggingface-hub sentencepiece wandb autoawq -q"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "YpdkZsMNylvp",
        "outputId": "6c2df234-1ce7-4cd2-a7e3-567e7536319f"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "import gc\n",
        "import torch\n",
        "from dataclasses import dataclass, field\n",
        "from typing import Any, Dict, List, NewType, Optional, Tuple\n",
        "import transformers\n",
        "from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, BitsAndBytesConfig\n",
        "from datasets import load_dataset\n",
        "from peft import LoraConfig, PeftModel, get_peft_model, prepare_model_for_kbit_training\n",
        "from trl import DPOTrainer\n",
        "import bitsandbytes as bnb\n",
        "from google.colab import\n",
        "\n",
        "\n",
        "model_name = \"teknium/OpenHermes-2.5-Mistral-7B\"\n",
        "\n",
        "new_model = \"OpenHermes-2.5-Mistral-7B-DPO-Math\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d8CvUgROUDw-"
      },
      "source": [
        "## Format DPO dataset\n",
        "\n",
        "First take a note of our Dataset here\n",
        "\n",
        "![](assets/2024-01-02-20-54-54.png)\n",
        "\n",
        "📌 DPO (Direct Preference Optimization) datasets for LLM training, typically consist of a collection of answers that are ranked by humans. This ranking is essential, as the RLHF process fine-tunes LLMs to output the preferred answer. \n",
        "\n",
        "📌 The structure of the dataset is straightforward: for each row, there is one chosen (preferred) answer, and one rejected answer. The goal of RLHF is to guide the model to output the preferred answer.\n",
        "\n",
        "📌 And Huggingface's `DPOTrainer` expects a very specific format for the dataset. \n",
        "\n",
        "📌 Since the model will be trained to directly optimize the preference of which sentence is the most relevant, given two sentences. We provide an example from the Anthropic/hh-rlhf dataset below.\n",
        "\n",
        "📌 To synthetically create DPO datasets for a set of prompts, you can create the answers with GPT-4/3.5 which will be your preferred answers, and with Llama-2-13b or similar class of models, create the rejected responses. \n",
        "\n",
        "It’s a smart way to bypass human feedback and only rely on models with different levels of size/performance."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "MCD77GZ60DOT",
        "outputId": "c7c6773c-5545-4fee-bfa3-6fa6d69c0f3f"
      },
      "outputs": [],
      "source": [
        "def format_message(role, content, tokenizer, add_generation_prompt=False):\n",
        "    if content:\n",
        "        message = {\"role\": role, \"content\": content}\n",
        "        return tokenizer.apply_chat_template([message], tokenize=False, add_generation_prompt=add_generation_prompt)\n",
        "    return \"\"\n",
        "\n",
        "def format_prompt_into_chatml(row_sample):\n",
        "    # Error handling for missing keys in row_sample\n",
        "    required_keys = ['system', 'question', 'chosen', 'rejected']\n",
        "    for key in required_keys:\n",
        "        if key not in row_sample:\n",
        "            # Handle missing key appropriately, e.g., raise an error or return a default value\n",
        "            raise ValueError(f\"Key '{key}' missing in row sample\")\n",
        "\n",
        "    system = format_message(\"system\", row_sample['system'], tokenizer)\n",
        "    prompt = format_message(\"user\", row_sample['question'], tokenizer, add_generation_prompt=True)\n",
        "    chosen = row_sample['chosen'] + \"\\n\"\n",
        "    rejected = row_sample['rejected'] + \"\\n\"\n",
        "\n",
        "    return {\n",
        "        \"prompt\": system + prompt,\n",
        "        \"chosen\": chosen,\n",
        "        \"rejected\": rejected,\n",
        "    }\n",
        "\n",
        "\n",
        "dataset = load_dataset(\"Intel/orca_dpo_pairs\")['train']\n",
        "\n",
        "# Save columns\n",
        "original_columns = dataset.column_names\n",
        "\n",
        "# Tokenizer\n",
        "tokenizer = AutoTokenizer.from_pretrained(model_name)\n",
        "tokenizer.pad_token = tokenizer.eos_token\n",
        "tokenizer.padding_side = \"left\"\n",
        "\n",
        "# Format dataset\n",
        "dataset = dataset.map(\n",
        "    format_prompt_into_chatml,\n",
        "    remove_columns=original_columns\n",
        ")\n",
        "\n",
        "# Print sample\n",
        "dataset[1]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DeT5eUK_UJgK"
      },
      "source": [
        "## Train model with DPO\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rKPILNOLR-aK"
      },
      "outputs": [],
      "source": [
        "\n",
        "@dataclass\n",
        "class DPOConfig(transformers.TrainingArguments):\n",
        "    \"\"\"\n",
        "    Arguments related to the DPO training process itself.\n",
        "    For all parameters, see:\n",
        "    https://huggingface.co/docs/transformers/v4.26.1/en/main_classes/trainer#transformers.TrainingArguments\n",
        "    \"\"\"\n",
        "\n",
        "    beta: Optional[float] = field(\n",
        "        default=0.1,\n",
        "        metadata={\"help\": \"The beta factor in DPO loss. Higher beta means less divergence from the initial policy.\"},\n",
        "    )\n",
        "    hub_model_revision: Optional[str] = field(\n",
        "        default=\"main\",\n",
        "        metadata={\"help\": (\"The Hub model branch to push the model to.\")},\n",
        "    )\n",
        "    logging_first_step: bool = field(\n",
        "        default=True,\n",
        "        metadata={\"help\": (\"Whether to log and evaluate the first global_step or not.\")},\n",
        "    )\n",
        "    max_prompt_length: Optional[int] = field(\n",
        "        default=None,\n",
        "        metadata={\"help\": (\"For DPO, the maximum length of the prompt to use for conditioning the model.\")},\n",
        "    )\n",
        "    max_length: Optional[int] = field(\n",
        "        default=None,\n",
        "        metadata={\"help\": (\"Used by TRL for reward model training, which tries to read this parameter in init.\")},\n",
        "    )\n",
        "    optim: Optional[str] = field(default=\"rmsprop\")\n",
        "    remove_unused_columns: bool = field(default=False)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Note on `DPOConfig` class - \n",
        "\n",
        "📌 When you instantiate `DPOConfig` with parameters such as `save_strategy=\"steps\"`, which are not explicitly defined in `DPOConfig`, Python's inheritance mechanism comes into play. Since `DPOConfig` is a subclass of `transformers.TrainingArguments`, it inherits all attributes and methods of the base class. Therefore, even if certain parameters like `save_strategy` are not explicitly defined in `DPOConfig`, they are valid as long as they are part of the `transformers.TrainingArguments`.\n",
        "\n",
        "📌 The `DPOConfig` class, derived from `transformers.TrainingArguments`, allows customization of training parameters specific to your fine-tuning task. \n",
        "\n",
        "📌 In the `DPOConfig` class, you've defined certain parameters like `beta`, `hub_model_revision`, `logging_first_step`, etc. These are additional or overridden parameters on top of the standard ones provided by `transformers.TrainingArguments`.\n",
        "\n",
        "📌 This mechanism allows your instance `training_args` to use parameters from both `DPOConfig` and `transformers.TrainingArguments`. \n",
        "\n",
        "📌 However, it's important to ensure that the parameters you are using in `training_args` are indeed valid and recognized by `transformers.TrainingArguments`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def train(model_name,\n",
        "          dataset,\n",
        "          tokenizer,\n",
        "          new_model,\n",
        "          #wandb_project: str = \"\",\n",
        "          #wandb_run_name: str = \"\",\n",
        "          #wandb_watch: str = \"\",  # options: false | gradients | all\n",
        "          #wandb_log_model: str = \"\",  # options: false | true\n",
        "          ):\n",
        "    peft_config = LoraConfig(\n",
        "        r=16,\n",
        "        lora_alpha=16,\n",
        "        lora_dropout=0.05,\n",
        "        bias=\"none\",\n",
        "        task_type=\"CAUSAL_LM\",\n",
        "        target_modules=List[str] =['k_proj', 'gate_proj', 'v_proj', 'up_proj', 'q_proj', 'o_proj', 'down_proj']\n",
        "    )\n",
        "    assert (\n",
        "        model_name\n",
        "    ), \"Please specify a --base_model, e.g. --base_model='huggyllama/llama-7b'\"\n",
        "\n",
        "    # Check if parameter passed or if set within environ\n",
        "    '''\n",
        "    use_wandb = len(wandb_project) > 0 or (\n",
        "        \"WANDB_PROJECT\" in os.environ and len(os.environ[\"WANDB_PROJECT\"]) > 0\n",
        "    )\n",
        "    # Only overwrite environ if wandb param passed\n",
        "    if len(wandb_project) > 0:\n",
        "        os.environ[\"WANDB_PROJECT\"] = wandb_project\n",
        "    if len(wandb_watch) > 0:\n",
        "        os.environ[\"WANDB_WATCH\"] = wandb_watch\n",
        "    if len(wandb_log_model) > 0:\n",
        "        os.environ[\"WANDB_LOG_MODEL\"] = wandb_log_model\n",
        "    '''\n",
        "\n",
        "    # Base Model\n",
        "    model = AutoModelForCausalLM.from_pretrained(\n",
        "        model_name,\n",
        "        torch_dtype=torch.float16,\n",
        "        load_in_4bit=True\n",
        "    )\n",
        "    model.config.use_cache = False\n",
        "\n",
        "    # Reference model\n",
        "    ref_model = AutoModelForCausalLM.from_pretrained(\n",
        "        model_name,\n",
        "        torch_dtype=torch.float16,\n",
        "        load_in_4bit=True\n",
        "    )\n",
        "\n",
        "    # Training arguments\n",
        "    training_args = DPOConfig(\n",
        "        num_train_epochs=3,\n",
        "        per_device_train_batch_size=1,\n",
        "        gradient_accumulation_steps=4,\n",
        "        gradient_checkpointing=True,\n",
        "        learning_rate=5e-5,\n",
        "        lr_scheduler_type=\"linear\",\n",
        "        max_steps=200,\n",
        "        save_strategy=\"no\",\n",
        "        logging_steps=1,\n",
        "        output_dir=new_model,\n",
        "        optim=\"paged_adamw_32bit\",\n",
        "        warmup_steps=100,\n",
        "        fp16=True,\n",
        "        # report_to=\"wandb\",\n",
        "    )\n",
        "\n",
        "    dpo_trainer = DPOTrainer(\n",
        "        model,\n",
        "        ref_model,\n",
        "        args=training_args,\n",
        "        train_dataset=dataset,\n",
        "        tokenizer=tokenizer,\n",
        "        peft_config=peft_config,\n",
        "        beta=0.1,\n",
        "        max_prompt_length=1024,\n",
        "        max_length=1536,\n",
        "    )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "dpo_trainer.train(model_name, dataset, tokenizer, new_model)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3LdhPpcrUM3H"
      },
      "source": [
        "## Save the finetuned model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "h7cIvxcTfBC4"
      },
      "outputs": [],
      "source": [
        "# Save artifacts\n",
        "dpo_trainer.model.save_pretrained(\"final_checkpoint\")\n",
        "tokenizer.save_pretrained(\"final_checkpoint\")\n",
        "\n",
        "# Clean up memory\n",
        "del dpo_trainer, model, ref_model\n",
        "gc.collect()\n",
        "torch.cuda.empty_cache()\n",
        "\n",
        "# Reload model in FP16 (instead of NF4)\n",
        "base_model = AutoModelForCausalLM.from_pretrained(\n",
        "    model_name,\n",
        "    return_dict=True,\n",
        "    torch_dtype=torch.float16,\n",
        ")\n",
        "tokenizer = AutoTokenizer.from_pretrained(model_name)\n",
        "\n",
        "# Merge base model with the adapter\n",
        "model = PeftModel.from_pretrained(base_model, \"final_checkpoint\")\n",
        "model = model.merge_and_unload()\n",
        "\n",
        "# Save model and tokenizer\n",
        "model.save_pretrained(new_model)\n",
        "tokenizer.save_pretrained(new_model)\n",
        "\n",
        "# Push them to the HF Hub\n",
        "# model.push_to_hub(new_model, use_temp_dir=False, token=hf_token)\n",
        "# tokenizer.push_to_hub(new_model, use_temp_dir=False, token=hf_token)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G6EFsmS4UOgV"
      },
      "source": [
        "## Inference"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def generate_chat_response(message, new_model):\n",
        "    tokenizer = AutoTokenizer.from_pretrained(new_model)\n",
        "    prompt = tokenizer.apply_chat_template(message, add_generation_prompt=True, tokenize=False)\n",
        "\n",
        "    chat_pipeline = pipeline(\n",
        "        \"text-generation\",\n",
        "        model=new_model,\n",
        "        tokenizer=tokenizer\n",
        "    )\n",
        "\n",
        "    sequences = chat_pipeline(\n",
        "        prompt,\n",
        "        do_sample=True,\n",
        "        temperature=0.8,\n",
        "        top_p=0.8,\n",
        "        num_return_sequences=1,\n",
        "        max_length=250,\n",
        "    )\n",
        "\n",
        "    return sequences[0]['generated_text']\n",
        "\n",
        "# Usage\n",
        "message = [\n",
        "    {\"role\": \"system\", \"content\": \"You are a friendly AI chatbot.\"},\n",
        "    {\"role\": \"user\", \"content\": \"Plan a holiday for the summer in Europe?\"}\n",
        "]\n",
        "\n",
        "generated_text = generate_chat_response(message, new_model)\n",
        "\n",
        "print(generated_text)\n"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "authorship_tag": "ABX9TyOJJCuqxZQnS1q+Fvz5+URG",
      "gpuType": "A100",
      "include_colab_link": true,
      "machine_shape": "hm",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "173769f6f465485f8848a11bf269850b": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_9083029642744c43b7705532cbe0cf79",
            "placeholder": "​",
            "style": "IPY_MODEL_d028a98caa13425b907ceb513119006e",
            "value": " 3/3 [00:11&lt;00:00,  2.89s/it]"
          }
        },
        "22773c721a7c4221a9c14cd388461d4c": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_6b54841f5de1482694c360095dae3039",
              "IPY_MODEL_448ccbc85e624ec3b3e71931a7ee4ff6",
              "IPY_MODEL_173769f6f465485f8848a11bf269850b"
            ],
            "layout": "IPY_MODEL_60978b9b4e8348f0a71ce3e35c73bcff"
          }
        },
        "448ccbc85e624ec3b3e71931a7ee4ff6": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_6e32854952b340008edca0139d3471d6",
            "max": 3,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_db6d7cfcdade4b4baa213a5d0abc07d7",
            "value": 3
          }
        },
        "60978b9b4e8348f0a71ce3e35c73bcff": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "6a38dcbaf4674b448329ac0a16587d2a": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "6b54841f5de1482694c360095dae3039": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_6a38dcbaf4674b448329ac0a16587d2a",
            "placeholder": "​",
            "style": "IPY_MODEL_7eaeada2158e493189449af91f643553",
            "value": "Loading checkpoint shards: 100%"
          }
        },
        "6e32854952b340008edca0139d3471d6": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "7eaeada2158e493189449af91f643553": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "9083029642744c43b7705532cbe0cf79": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "d028a98caa13425b907ceb513119006e": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "db6d7cfcdade4b4baa213a5d0abc07d7": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        }
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
